﻿#include "sobel.h"


/*
* Sobel
*
*
*/
char SobelFilter(matrix inmat, matrix outmat, matrix table) {
    int r, c, i, j, chan, index;
    int sum, t;
    table.sum = 8;

    for (r = 0; r < inmat.h; r++) {
        for (c = 0; c < inmat.w; c++) {
            for (chan = 0; chan < inmat.channel; chan++) {
                //printf("indata:\n");
                t = 0;
                for (i = 0; i < table.h; i++) {
                    for (j = 0; j < table.w; j++) {
                        index = i * table.w + j;
                        if ((r + i - (table.h >> 1)) < 0 || c + j - (table.w >> 1) < 0 || (r + i - (table.h >> 1)) >= inmat.h || c + j - (table.w >> 1) >= inmat.w)
                            t = 0;      //padding value
                        else
                            t = inmat.data[((r + i - (table.h >> 1)) * inmat.w + c + j - (table.w >> 1)) * inmat.channel + chan];
                        t += ((int*)table.d)[index] * inmat.data[((r + i - (table.h >> 1)) * inmat.w + c + j - (table.w >> 1)) * inmat.channel + chan];

                        //printf("%d\t", dbuf.data[i * table.w + j]);
                    }
                    //std::cout << std::endl;
                }
                //printf("sum:%d,t:%d", sum, t);
                t /= table.sum;
                outmat.data[(r * outmat.w + c) * outmat.channel + chan] = (uchar)(clip(t, 0, 255));
            }
        }
    }
    return OK;
}


inline int GetLvGray(int x, int arr[]) {
    if (x < arr[0])
        return 0;
    if (x < arr[1])
        return 1;
    if (x < arr[2])
        return 2;
    if (x < arr[3])
        return 3;
    return 4;
}

/*
* SobelXY
*
*
*/
char SobelXY(matrix inmat, matrix outmat) {
    matrix tablex, tabley;
    int r, c, i, j, chan, index;
    int tx[3][3] = { {-1,0,1},{-2,0,2},{-1,0,1} };
    int ty[3][3] = { {-1,-2,-1},{0,0,0},{1,2,1} };
    int arrlv[4] = { 51,102,153,204 };
    float ws[5] = { 0,0.1,0.3,1 ,1 };
    double yns[4] = { 0.2,0.4,0.6,0.8 };
    int belta = 1;
    for (int j = 0; j < 4; j++) {
        arrlv[j] = (int)pow(yns[j], belta) * 255;
    }

    int x, y, t;
    tablex.d = tx;
    tabley.d = ty;
    tablex.w = tablex.h = tabley.w = tablex.h = 3;
    tablex.channel = 1;
    tabley.sum = tablex.sum = 8;
    if (inmat.channel != 1) {
        printf("<SobelXY>warning:\tinput mulity channel image!\n");
    }
    for (r = 0; r < inmat.h; r++) {
        for (c = 0; c < inmat.w; c++) {
            for (chan = 0; chan < inmat.channel; chan++) {
                if (r == 412 && c == 333) {
                    std::cout << "-------------------------------------" << std::endl;
                }
                x = y = 0;
                if (!(r<1 || r>inmat.h - 2 || c<1 || c>inmat.w - 2))   
                    for (i = 0; i < tablex.h; i++) {
                        for (j = 0; j < tablex.w; j++) {
                            index = i * tablex.w + j;
                            t = inmat.data[((r + i - (tablex.h >> 1)) * inmat.w + c + j - (tablex.w >> 1)) * inmat.channel + chan];
                            y += ((int*)tabley.d)[index] * t;
                            x += ((int*)tablex.d)[index] * t;
                            //printf("%dx%d=%d\t", ((int*)tablex.d)[index],t,x);
                        }
                        // std::cout << std::endl;
                    }
                //printf("sum:%d,t:%d", sum, t);
                x = abs(x) >> 2;
                y = abs(y) >> 2;
                t = (int)sqrt((x * x) + (y * y));
                // printf("res:%d\n", t);
                if (t < 0 || t>255) {
                    printf("<SobelXY>warning! out of range t=%d\n", t);
                }
                t = GetLvGray(clip(t, 0, 255), arrlv);
                //t = inmat.data[(r * outmat.w + c) * outmat.channel + chan] * ws[t];

                outmat.data[(r * outmat.w + c) * outmat.channel + chan] = (uchar)(t*63);
            }
        }
    }
    return OK;
}

